package snippet;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.TreeSet;
import java.util.zip.DataFormatException;

class CSVLoader {
	private static final String DELIMITER = "\\s*(\\s|,)\\s*";
	double[][] data;
	String[] headers;
	TreeSet<Integer> ignoredColumns;
	String[][] ignored;
	
	private final boolean containHeader;
	public CSVLoader(final boolean containHeader){
		this.containHeader=containHeader;
		ignoredColumns = new TreeSet<Integer>();
	}
	public void ignore(int column){
		ignoredColumns.add(new Integer(column));
	}
	
	public void load(final String filemame) throws FileNotFoundException, DataFormatException{
		load(new File(filemame));
	}
	public void load(final File file) throws FileNotFoundException, DataFormatException{
		load(new Scanner(file));
	}
	public void load(final InputStream in) throws DataFormatException{
		load(new Scanner(in));
	}
	public void load(final InputStreamReader in) throws DataFormatException{
		load(new Scanner(in));
	}
	public void load(final Scanner scan) throws DataFormatException{
		readHeader(scan,containHeader);
		readData(scan);
		scan.close();
	}
	private void readData(Scanner scan) throws DataFormatException {
		LinkedList<String[]> content = new LinkedList<String[]>();
		String current;
		while(scan.hasNextLine() && !(current=scan.nextLine()).isEmpty())
			content.add(current.split(DELIMITER));
		final int columns	= (headers != null?headers.length:(content.isEmpty()?0:content.get(0).length)) - ignoredColumns.size();
		final int rows		= content.size();
		this.data 			= new double[rows][columns];
		int row=0;
		
		ignored = ignoredColumns.size()>0?new String[rows][ignoredColumns.size()]:null;
		
		while(!content.isEmpty()){
			final String[] raw = content.remove();
			if(raw.length != columns+ignoredColumns.size()) throw new DataFormatException("Bad number of columns in row "+row+", it is "+raw.length+" and must be "+(columns+ignoredColumns.size()));
			
			Iterator<Integer> iterator	= ignoredColumns.iterator();
			int toIgnore				= iterator.hasNext()?iterator.next():Integer.MAX_VALUE;
			
			for(int column=0,pos=0,ignorePosition=0;pos<raw.length;pos++){
				if(column < toIgnore) data[row][column++]=raw[pos].equals("NA")?Double.NaN:Double.parseDouble(raw[pos]);
				else{
					ignored[row][ignorePosition++]	= raw[pos];
					toIgnore = iterator.hasNext()?iterator.next():Integer.MAX_VALUE;
				}
			}
			++row;
		}
	}
	private void readHeader(final Scanner scan,boolean containHeader){
		this.headers = containHeader?scan.nextLine().split(DELIMITER):null;
	}
}
